/**
 * Copyright (c) 2016-Now http://www.javamis.com All rights reserved.
 * No deletion without permission, or be held responsible to law.
 */
package com.javamis.common.aop;
import com.alibaba.fastjson.JSON;
import com.javamis.common.logger.AccessLog;
import com.javamis.common.logger.Logger;
import com.javamis.common.logger.single.AccessLogSingleton;
import com.javamis.config.shiro.ShiroUtils;
import com.javamis.modular.system.dao.AccessLogMapper;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import static com.javamis.common.util.HttpRequestUtil.getIpAddress;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * @name:   日志AOP横向切面类.
 * @version:1.0.2
 * @author:	HuiJia
 * @QQ号： 	763236277
 * @QQ群： 	327773608
 * @邮箱: 	javamis@163.com
 * @site：	http://www.javamis.com
 */
@Aspect
@Component
public class LoggerAop {
	@Autowired
	private AccessLogMapper accessLogMapper;
	/**
     * 此处的切点是注解的方式，也可以用包名的方式达到相同的效果
     */
    @Pointcut("@annotation(com.javamis.common.logger.Logger)")
    public void logger(){}
 
 
    /**
     * 环绕增强，相当于MethodInterceptor
     */
    @Around("logger()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
        Object obj = null;
        long time = System.currentTimeMillis();
        try {
            obj =  joinPoint.proceed();
            time = System.currentTimeMillis() - time;
            return obj;
        } finally {
            try {
            	addLogger(joinPoint,obj,time);
            }catch (Exception e){
                System.out.println("AccessLogAop 操作失败：" + e.getMessage());
                e.printStackTrace();
            }
        }
    }
 
    private void addLogger(JoinPoint joinPoint, Object res, long time){
        MethodSignature signature = (MethodSignature)joinPoint.getSignature();
        AccessLog accessLog = new AccessLog();
        accessLog.setRunTime((int)time);
        accessLog.setReturnValue(JSON.toJSONString(res));
        accessLog.setArgs(JSON.toJSONString(joinPoint.getArgs()));
        accessLog.setOperTime(new Date());
        accessLog.setAddress(signature.getDeclaringTypeName() + "/" + signature.getName());
        accessLog.setOperCode(ShiroUtils.getShiroInfoObj().getUserCode());
        accessLog.setOperUser(ShiroUtils.getShiroInfoObj().getUserName());
        accessLog.setIpAddress(getIpAddress());
        Logger annotation = signature.getMethod().getAnnotation(Logger.class);
        if(annotation != null){
        	accessLog.setLevel(annotation.level());
        	accessLog.setDetails(getDetail(((MethodSignature)joinPoint.getSignature()).getParameterNames(),joinPoint.getArgs(),annotation));
        	accessLog.setType(annotation.type().getValue());
        	accessLog.setModular(annotation.unit().getValue());
        }
        //TODO 这里保存日志
        //System.out.println("记录日志:" + accessLog.toString());
        AccessLogSingleton.getInstance().runLog(accessLogMapper,accessLog);
    }
 
    /**
     * 对当前登录用户和占位符处理
     * @param argNames 方法参数名称数组
     * @param args 方法参数数组
     * @param annotation 注解信息
     * @return 返回处理后的描述
     */
    private String getDetail(String[] argNames, Object[] args, Logger annotation){
 
        Map<Object, Object> map = new HashMap<>(4);
        for(int i = 0;i < argNames.length;i++){
            map.put(argNames[i],args[i]);
        }
 
        String detail = annotation.detail();
        try {
            detail = "'" + "#{currentUserName}" + "'=》" + annotation.detail();
            for (Map.Entry<Object, Object> entry : map.entrySet()) {
                Object k = entry.getKey();
                Object v = entry.getValue();
                detail = detail.replace("{{" + k + "}}", JSON.toJSONString(v));
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return detail;
    }
 
    @Before("logger()")
    public void doBeforeAdvice(JoinPoint joinPoint){
        System.out.println("进入方法前执行.....");
    }
 
    /**
     * 处理完请求，返回内容
     * @param ret
     */
    @AfterReturning(returning = "ret", pointcut = "logger()")
    public void doAfterReturning(Object ret) {
        System.out.println("方法的返回值 : " + ret);
    }
 
    /**
     * 后置异常通知
     */
    @AfterThrowing("logger()")
    public void throwss(JoinPoint jp){
        System.out.println("方法异常时执行.....");
    }
 
 
    /**
     * 后置最终通知,final增强，不管是抛出异常或者正常退出都会执行
     */
    @After("logger()")
    public void after(JoinPoint jp){
        System.out.println("方法最后执行.....");
    }

}
